package com.cskaoyan.javase.oop2._2polymorphic._2advantage._0introduction;

/**
 * 多态的优缺点以及向下转型
 * 多态是面向对象三大特征之一，它基于继承而实现，是面向对象思想的集大成者。
 * 接下来我们研究一下，它的优缺点。我们通过一个案例：
 * 科学家要收集动物的叫声去研究，先要收集猫，狗两种动物的叫声研究。
 * 随后又扩展到其它动物，最后又需要研究人类。
 * 但是人类比较特殊,如果想要找人配合研究,需要加钱
 * 所以人类有自身独有的方法: 加钱
 * 人在叫之前,得加钱
 *
 * 写一个方法,方法的形参写父类类型,在调用方法时,传入不同的子类对象,这样就能够发生多态现象
 * 从这个案例，我们其实就可以大致总结多态的优点了：
 *      1.要实现多态必须要继承，而继承提高了代码复用率，提升了程序的可维护性。（继承保证）
 *      2. 有了多态后，用父类引用指向不同子类对象，只需要调用同名方法，就能自动根据不同子类对象
 *          得出不同的行为。这大幅度简化了代码，提升了程序的扩展性。（多态保证）
 *
 *
 * 多态肯定是有缺点的，而且很明显。
 * 由于多态中，使用父类引用指向子类对象，父类引用限制了子类对象的功能，这意味着：
 * 子类独有的成员是无法使用父类引用访问的。
 * 这时就需要做强转来解决这个问题.
 *
 * Java当中,提供了判断能否进行强转的语法,使用instanceof关键字
 * 语法:
 *      引用/对象名 instanceof 类名
 * 用来判断左边引用指向的对象,是否是后面类名的对象或者子类对象
 * 该判断结构,如果是,就返回true,否则返回false
 * 实际开发中,多数情况,它会配合if去使用.
 * 特殊的: null instanceof 任何类名 结果都是false,这里是不会产生空指针异常的
 *
 * 为什么能够判断强转?如何判断?
 * 当该结构返回true时,意味着引用指向的对象是,后面类名的对象或者子类对象
 * 这就意味着该引用可以强转成后面类名类型的引用
 *
 * 最后要强调的是,
 * 强转,向下转型,在开发中,并不少见
 * 如果不是百分百确定,一定不会出现问题,
 * 那么建议在做强转之前,先判断,在if中做强转
 * 避免类型转换异常
 *
 *
 * @since 15:14
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // collectCatVoice(new Cat());
        collectAnimalVoice(new Cat());
        collectAnimalVoice(new Dog());
        collectAnimalVoice(new Pig());

        collectAnimalVoice(new Person());
    }

    // 写一个方法来收集研究所有动物的叫声
    public static void collectAnimalVoice(Animal a) {
        /*
            a引用是父类引用
            父类引用会限制访问范围为"父类"
            子类中独有的成员是访问不到的
            而实际上Person类中是有加钱行为的
            只不过由于父类引用限制,调用不了
            所以要恢复子类引用
            这里要:
            父类引用 --> 子类引用
            向下转型,是强制类型转换
         */
        // 做一次强转,要做判断
        if (a instanceof Person) {
            // 可以强转
            Person p = (Person) a;
            p.addMoney();
        }
        // 抓一只动物过来
        a.shout();
        // 收集研究
    }

    /*// 写一个方法来收集研究猫的叫声
    public static void collectCatVoice(Cat c){
        // 抓一只猫过来,让它叫
        c.shout();
        // 收集研究
    }*/
}

// 定义父类
class Animal {
    String name;
    int age;

    public void shout() {
        System.out.println("都会叫!");
    }
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("喵喵喵~");
    }
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("汪汪汪~");
    }
}

class Pig extends Animal {
    @Override
    public void shout() {
        System.out.println("小猪佩奇!");
    }
}

class Person extends Animal {
    @Override
    public void shout() {
        System.out.println("嘤嘤嘤~");
    }

    public void addMoney(){
        System.out.println("加钱,给钱就好办事!");
    }
}